package pira.db.excute;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.neo4j.graphdb.Node;

import pira.db.ui.GraphDBUI;
import pira.db.ui.SubDBUI;
import pira.elements.Paper;
import pira.utils.Log;

// use to handle the format of logs and extract useful info
public class HandleLog {

	private enum State {
		READY, BEGIN, TITLE, AUTHORS, ENDFILE,
	}

	private FileReader fr;
	private BufferedReader br;

	private GraphDBUI gdbui;
	private SubDBUI sdbui;
	
	public void applyToDB() {
		
		gdbui = new GraphDBUI();
		File[] list = new File("cited_logs").listFiles();
		Log log = new Log("outputs/Papers_citation_number.txt");
		String str = null;
		int totalNumber = 0;
		for (File file : list) {
			System.out.println(file.getName());
			gdbui.tx = gdbui.getGraphDatabaseService().beginTx();
			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);

				String line = null;
				State s = State.READY;

				// node ID
				long id = 0;

				// citation number
				int num = 0;

				// citation count
				int count = 0;

				// internal citation count
				int iCount = 0;

				// external citation count
				int eCount = 0;

				// current node
				Node myPaper = null;

				// citation paper title
				String title = null;

				// change between states
				while (br.ready() && s != State.ENDFILE) {
					line = br.readLine();
					switch (s) {
					case READY:
						if (line.equals("")) {
							s = State.BEGIN;
							System.out.println();
						}
						break;
					case BEGIN:
						if (!line.equals(DBScanner.STATISTIC)) {
							s = State.TITLE;
							totalNumber++;
							id = Long.parseLong(line.split("\t")[0]);
							num = Integer.parseInt(line.split("\t")[1]);
							count = 0;
							iCount = 0;
							eCount = 0;

							log.write(id + "\tCited by " + num + " times.\n");

							// get current node
							myPaper = gdbui.getGraphDatabaseService()
									.getNodeById(id);

							// set "find" property for current node
							myPaper.setProperty("find", "yes");

							// set "cited times" property for current node
							myPaper.setProperty("cite times", "" + num);
						} else
							s = State.ENDFILE;
						break;
					case TITLE:
						count++;
						if (count <= num) {
							System.out.println(count + "  :  TITLE : " + line);
							title = line;
							s = State.AUTHORS;
						} else {
							System.out.println("Errors.");
							s = State.ENDFILE;
						}
						break;
					case AUTHORS:
						if (count < num)
							s = State.TITLE;
						else
							s = State.READY;

						String[] authors = line.split(":\t");
						for (int i = 1; i < authors.length; i++)
							System.out.println(authors[i]);

						// add citation to database
						int r = gdbui.addCitation(myPaper, title, authors);
						if (r == 1)
							iCount++;
						else if (r == 2)
							eCount++;
						else
							System.err
									.println("Errors when add citation to DB.");

						if (count == num) {
							str = "\tCited by internal nodes " + iCount
									+ " times;by external nodes " + eCount
									+ " times.\n\n";
							log.write(str);

							// set internal and external cited times for the
							// current node
							myPaper.setProperty("internal cited times", ""
									+ iCount);
							myPaper.setProperty("external cited times", ""
									+ eCount);
						}
						break;
					}
				}
				gdbui.tx.success();
			} catch (FileNotFoundException e) {
				gdbui.tx.failure();
				e.printStackTrace();
			} catch (IOException e) {
				gdbui.tx.failure();
				e.printStackTrace();
			} finally {
				gdbui.tx.finish();
			}
		}
		log.write("Totally there're " + totalNumber
				+ " papers are found in CiteSeerX.\n");
		log.close();
		gdbui.getGraphDatabaseService().shutdown();
	}

	public void readCitedLogs() {
		Log out = new Log("outputs/Paper_found_in_CiteSeerX.txt");
		File[] list = new File("cited_logs").listFiles();
		String str = null;
		int totalNumber = 0;
		
		for (File file : list) {
//			str = "\n" + file.getName() + " : \n";
//			out.write(str);
			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);
				String line = null;
				long paperID = -1;
				int linesToSkip = 0;
				int linesAlreadySkip = 0;
				
				/*
				 * 3 states
				 * 0: ready
				 * 1: read paper ID
				 * 2: skip cited papers
				 */
				int state= 0;
				
				label:	
				while (br.ready()) {
					line = br.readLine();
					switch (state) {
					case 0:
						if (line.equals("")) {
							state = 1;
						}
						continue label;
					case 1:
						if (line.equals(DBScanner.STATISTIC))
							break label;
						paperID = Long.parseLong(line.split("\t")[0]);
//						Node p = gdbui.getGraphDatabaseService().getNodeById(paperID);
//						String title = (String) p.getProperty("title");
//						String[] authors = (String[]) p.getProperty("authors");
						
						// start crawl the references for the paper
//						CiteSeerX csx = new CiteSeerX(title, authors);
//						csx.parseReference();
						
						linesToSkip = Integer.parseInt(line.split("\t")[1]) * 2;
						totalNumber++;
//						out.write(totalNumber + "\t" + paperID + "\t" + title + "\n");
						System.out.println(totalNumber + "\t" + paperID);
						out.write(totalNumber + "\t" + paperID + "\n");
						linesAlreadySkip = 0;
						state = 2;
						break;
					case 2:
						if (line.equals("")) {
							state = 1;
							break;
						}
						linesAlreadySkip++;
						if (linesAlreadySkip == linesToSkip)
							state = 0;
						break;
					}
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		str = "Totally, " + totalNumber + " papers are found in CiteSeerX.\n";
		System.out.println(str);
		out.write(str);
		out.close();
	}

	public void applyToNewDB() {
		
		long startTime = System.currentTimeMillis();
		gdbui = new GraphDBUI();
		sdbui = new SubDBUI();
		File[] list = new File("cited_logs").listFiles();
		Log log = new Log("outputs/Papers_citation_number.txt");
		int totalNumber = 0;
		for (File file : list) {
			System.out.println(file.getName());
			sdbui.tx = sdbui.getGraphDatabaseService().beginTx();
			try {
				fr = new FileReader(file);
				br = new BufferedReader(fr);

				String line = null;
				State s = State.READY;

				// node ID in old DB
				long oldId = 0;
				
				// node ID in SubDB
				long newId = 0;

				// citation number
				int num = 0;

				// citation count
				int count = 0;

				// current node
				Node myPaper = null;

				// citation paper title
				String title = null;

				// change between states
				while (br.ready() && s != State.ENDFILE) {
					line = br.readLine();
					switch (s) {
					case READY:
						if (line.equals("")) {
							s = State.BEGIN;
						}
						break;
					case BEGIN:
						if (!line.equals(DBScanner.STATISTIC)) {
							s = State.TITLE;
							totalNumber++;
							oldId = Long.parseLong(line.split("\t")[0]);
							num = Integer.parseInt(line.split("\t")[1]);
							count = 0;
System.out.println("\nThe " + totalNumber + " th paper!!! ID : " + oldId);

							// get node in old DB
							Node oldNode = gdbui.getGraphDatabaseService().getNodeById(oldId);
							
							// get his new ID in SubDB
							newId = (Long) oldNode.getProperty("new id");
							
							// get the node in SubDB
							myPaper = sdbui.getGraphDatabaseService()
									.getNodeById(newId);

							// set "cited times" property for current node
							myPaper.setProperty(Paper.CITEDTIMES, num);
							
							log.write(newId + "\tCited by " + num + " times.\n");
						} else
							s = State.ENDFILE;
						break;
					case TITLE:
						if (line.equals("")) {
							s = State.BEGIN;
							break;
						}
						count++;
						if (count <= num) {
							title = line;
							s = State.AUTHORS;
						} else {
							System.out.println("Errors.");
							s = State.ENDFILE;
						}
						break;
					case AUTHORS:
						if (count < num)
							s = State.TITLE;
						else
							s = State.READY;

						String[] strs = line.split(":\t");
						String[] authors = new String[strs.length-1];
						
						for (int i = 0; i < strs.length-1; i++)
							authors[i] = strs[i+1];
						
						// add citation to database
						sdbui.addCitation(gdbui, myPaper, title, authors);
						
						if (count == num) {
							// set the Global Node 
							Node gnode = sdbui.getGraphDatabaseService().getNodeById(SubDBUI.GLOBALNODEID);
							gnode.setProperty(SubDBUI.PAPERNUMBER, sdbui.paperNumber);
							gnode.setProperty(SubDBUI.AUTHORNUMBER, sdbui.authorNumber);
							gnode.setProperty(SubDBUI.ALLNODENUMBER, sdbui.paperNumber + sdbui.authorNumber + 2);
							
							sdbui.tx.success();
							sdbui.tx.finish();
							sdbui.tx = sdbui.getGraphDatabaseService().beginTx();
						}
						break;
					case ENDFILE:
						break;
					}
				}
				sdbui.tx.success();
			} catch (FileNotFoundException e) {
				sdbui.tx.failure();
				e.printStackTrace();
			} catch (IOException e) {
				sdbui.tx.failure();
				e.printStackTrace();
			} finally {
				sdbui.tx.finish();
			}
		}
		sdbui.getGraphDatabaseService().shutdown();
		gdbui.getGraphDatabaseService().shutdown();
		log.write("Totally there're " + totalNumber
				+ " papers are found in CiteSeerX.\n");
		log.write("Run " + (System.currentTimeMillis() - startTime)/1000 + " seconds.\n");
		log.close();
	}
	
	public static void main(String[] args) {
		HandleLog hl = new HandleLog();
//		hl.applyToDB();
//		hl.readCitedLogs();
		hl.applyToNewDB();
	}

}
